package org.lilred.nzbberry.controllers;

import java.util.Vector;

import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.EncodedImage;
import net.rim.device.api.system.GIFEncodedImage;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.BasicEditField;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.Menu;

import org.json.me.JSONArray;
import org.json.me.JSONException;
import org.json.me.JSONObject;
import org.lilred.nzbberry.models.ConfigModel;
import org.lilred.nzbberry.observer.Observable;
import org.lilred.nzbberry.observer.Observer;
import org.lilred.nzbberry.ui.AnimatedGIFField;
import org.lilred.nzbberry.util.EscapedString;
import org.lilred.nzbberry.views.AppView;
import org.lilred.nzbberry.views.ConfigView;
import org.lilred.nzbberry.webservice.RequestsOutput;
import org.lilred.nzbberry.webservice.SabnzbdActionClient;
import org.lilred.nzbberry.webservice.SabnzbdOutputClient;

public class ConfigController extends PageController implements FieldChangeListener, RequestsOutput, Observable {
	ConfigView configView;
	Vector observers = new Vector();
	public ConfigController() {
		configView = new ConfigView() {
			protected void onVisibilityChange(boolean visible) {
				if (visible) {
					validateSettings();
					refresh();
				}
			}
		};
		view = configView;
		configView.addressEditField.setChangeListener(this);
		String address = ConfigModel.getConfig().getSabnzbdAddress();
		configView.addressEditField.setText(address);
		configView.apiKeyEditField.setChangeListener(this);
		String apiKey = ConfigModel.getConfig().getSabnzbdApiKey();
		configView.apiKeyEditField.setText(apiKey);
		configView.validateButton.setChangeListener(this);
		configView.clearWarningsButton.setChangeListener(this);
	}
	
	public void fieldChanged(Field field, int context) {
		if (field == configView.addressEditField && context == 1) {
			String newAddress = configView.addressEditField.getText().trim();
			String oldAddress = ConfigModel.getConfig().getSabnzbdAddress();
			if (oldAddress.compareTo(newAddress) != 0) {
				ConfigModel.getConfig().setSabnzbdAddress(newAddress);
				validateSettings();
			}
		} else if (field == configView.apiKeyEditField && context == 1) {
			String newApiKey = configView.apiKeyEditField.getText().trim();
			String oldApiKey = ConfigModel.getConfig().getSabnzbdApiKey();
			if (oldApiKey.compareTo(newApiKey) != 0) {
				ConfigModel.getConfig().setSabnzbdApiKey(newApiKey);
				validateSettings();
			}
		} else if (field == configView.validateButton) {
			validateSettings();
		} else if (field == configView.clearWarningsButton) {
			SabnzbdActionClient clearWarningsClient = new SabnzbdActionClient();
			clearWarningsClient.clearWarnings();
		} else if (field == configView.refreshWarningsButton) {
			refresh();
		}
	}
	
	protected void validateSettings() {
		validateAddress();
		validateApiKey();
	}

	private void validateAddress() {
		String address = configView.addressEditField.getText().trim();
		configView.addressManager.setImage(new AnimatedGIFField((GIFEncodedImage) EncodedImage.getEncodedImageResource("ajaxloader.gif"), AnimatedGIFField.RIGHT));
		AddressValidator validator = new AddressValidator(address);
		validator.start();
	}
	
	private void validateApiKey() {
		String apiKey = configView.apiKeyEditField.getText().trim();
		configView.apiKeyManager.setImage(new AnimatedGIFField((GIFEncodedImage) EncodedImage.getEncodedImageResource("ajaxloader.gif"), AnimatedGIFField.RIGHT));
		ApiKeyValidator validator = new ApiKeyValidator(apiKey);
		validator.start();
	}
	
	public void refresh() {
		SabnzbdOutputClient warningsOutputClient = new SabnzbdOutputClient("warnings", this);
		for(int i = 0; i < observers.size(); i++) {
			((Observer) observers.elementAt(i)).updateObserver(this, AppController.STARTED);
		}
		warningsOutputClient.start();
	}
	
	private class ApiKeyValidator implements RequestsOutput {
		String key;
		public ApiKeyValidator(String key) {
			this.key = key;
		}
		public void start() {
			new SabnzbdOutputClient("get_cats", this).start();
		}
		public void webserviceOutputReceived(JSONObject o) {
			try {
				JSONArray categories = o.getJSONArray("categories");
				configView.apiKeyManager.setImage(new BitmapField(Bitmap.getBitmapResource("success.png"), BitmapField.RIGHT));
			} catch (Exception e) {
				webserviceRequestFailed();
			}
		}

		public void webserviceRequestFailed() {
			if (configView.apiKeyEditField.getText().trim().compareTo(key) == 0)
				configView.apiKeyManager.setImage(new BitmapField(Bitmap.getBitmapResource("failure.png"), BitmapField.RIGHT));
		}
	}
	
	private class AddressValidator implements RequestsOutput {
		String address;
		public AddressValidator(String address) {
			this.address = address;
		}
		public void start() {
			new SabnzbdOutputClient("version", this).start();
		}
		
		public void webserviceOutputReceived(JSONObject o) {
			try {
				configView.addressManager.setImage(new BitmapField(Bitmap.getBitmapResource("success.png"), BitmapField.RIGHT));
			} catch (Exception e) {
				webserviceRequestFailed();
			}
		}

		public void webserviceRequestFailed() {
			if (configView.addressEditField.getText().trim().compareTo(address) == 0)
				configView.addressManager.setImage(new BitmapField(Bitmap.getBitmapResource("failure.png"), BitmapField.RIGHT));
		}
	}

	public void webserviceOutputReceived(JSONObject jobj) {
		try {
			final JSONArray warningsArray = jobj.getJSONArray("warnings");
			AppView.getInstance().appManager.configButton.setBadges(warningsArray.length());
			//configView.warningsSettings.setTitleText("Warnings (" + warningsArray.length() + ")");
			final BasicEditField[] warningEditFieldArray = new BasicEditField[warningsArray.length()];
			for (int i = 0; i < warningsArray.length(); i++) {
				warningEditFieldArray[i] = new BasicEditField(BasicEditField.READONLY);
				warningEditFieldArray[i].setText(EscapedString.parse(warningsArray.getString(i)) + '\n');
			}
			UiApplication.getUiApplication().invokeLater(new Runnable() {
				public void run() {
					configView.warningsManager.deleteAll();
					if (warningsArray.length() > 0) configView.warningsManager.add(configView.clearWarningsButton);
					else configView.warningsManager.add(new LabelField("No warnings"));
					for (int i = 0; i < warningsArray.length(); i++) {
						configView.warningsManager.add(warningEditFieldArray[i]);
					}
					configView.warningsManager.add(configView.refreshWarningsButton);
					
				}
			});
			for (int i = 0; i < observers.size(); i++) {
				((Observer) observers.elementAt(i)).updateObserver(this, AppController.COMPLETED);
			}
		} catch (JSONException e) {
			webserviceRequestFailed();
			for (int i = 0; i < observers.size(); i++) {
				((Observer) observers.elementAt(i)).updateObserver(this, AppController.ERROR);
			}
		}
	}

	public void webserviceRequestFailed() {
		// TODO Auto-generated method stub
		
	}

	public void registerObserver(Observer o) {
		observers.addElement(o);
	}

	public Menu makeMenu(Menu menu) {
		menu.add(validateSettingsMenuItem);
		menu.add(refreshWarningsMenuItem);
		return menu;
	}
	
	public MenuItem validateSettingsMenuItem = new MenuItem("Validate Settings", 10, 10) {
		public void run() { validateSettings(); }
	};
	
	public MenuItem refreshWarningsMenuItem = new MenuItem("Refresh Warnings", 20, 20) {
		public void run() { refresh(); }
	};
}
